namespace tt{
namespace utils{

namespace impl{

//////////////////////////////////////////////////////////////////////////
template<typename CharType, Size MaxLen>
class StaticBuffer
{
public:
	StaticBuffer(Size max_len)
	{
		max_len;
	}

	Size size()
	{
		return MaxLen;
	}

	CharType* buffer()
	{
		return m_buffer;
	}

private:
	CharType m_buffer[MaxLen];
};

//////////////////////////////////////////////////////////////////////////
template<typename CharType>
class DynamicBuffer
{
public:
	DynamicBuffer(Size max_len)
	: m_buffer(max_len)
	{

	}

	Size size()
	{
		return m_buffer.size();
	}

	CharType* buffer()
	{
		return &m_buffer.front();
	}

private:
	typename core::Vector<CharType>::Type m_buffer;
};

//////////////////////////////////////////////////////////////////////////
Size from_ansi(CharW* dst, Size dstSize, const Char* src, Size srcSize);
Size from_ansi_count(const Char* src, Size srcSize);
Size to_ansi(Char* dst, Size dstSize, const CharW* src, Size srcSize);
Size to_ansi_count(const CharW* src, Size srcSize);

Size from_utf8(CharW* dst, Size dstSize, const Char* src, Size srcSize);
Size from_utf8_count(const Char* src, Size srcSize);
Size to_utf8(Char* dst, Size dstSize, const CharW* src, Size srcSize);
Size to_utf8_count(const CharW* src, Size srcSize);

} //namespace impl

//////////////////////////////////////////////////////////////////////////
namespace impl{

template<typename Buffer>
StringW from_ansi( const Char* ansiString )
{
	Size ansiStringLen = strlen(ansiString);
	Size widesize = impl::from_ansi_count(ansiString, ansiStringLen);
	if (widesize == -1)
	{
		ttThrow("Error in conversion.");
	}

	Buffer buffer(widesize);
	if(widesize > buffer.size())
	{
		ttThrow("Error in conversion.");
	}

	Size convresult = impl::from_ansi(buffer.buffer(), buffer.size(), ansiString, ansiStringLen);

	if (convresult != widesize)
	{
		ttThrow("La falla!");
	}

	if(widesize > 1)
		return StringW(buffer.buffer(), buffer.buffer() + widesize);

	return StringW();
}

template<typename Buffer>
String to_ansi( const CharW* wideString )
{
	Size wideStringLen = wcslen(wideString);
	Size ansi_size = impl::to_ansi_count(wideString, wideStringLen);
	if (ansi_size == -1)
	{
		ttThrow("Error in conversion.");
	}

	Buffer buffer(ansi_size);
	if(ansi_size > buffer.size())
	{
		ttThrow("Error in conversion.");
	}

	Size convresult = impl::to_ansi(buffer.buffer(), buffer.size(), wideString, wideStringLen);

	if (convresult != ansi_size)
	{
		ttThrow("La falla!");
	}

	if(ansi_size > 1)
		return String(buffer.buffer(), buffer.buffer() + ansi_size);

	return String();
}

} //namespace impl

//////////////////////////////////////////////////////////////////////////
template<Int MaxLen>
StringW from_ansi(const Char* ansi_string)
{
	return impl::from_ansi< impl::StaticBuffer<CharW, MaxLen> >(ansi_string);
}

inline
StringW from_ansi_1024(const Char* ansi_string)
{
	return from_ansi<1024>(ansi_string);
}

template<Int MaxLen>
StringW from_ansi(const String& ansi_string)
{
	return from_ansi<MaxLen>(ansi_string.c_str());
}

inline
StringW from_ansi_1024(const String& ansi_string)
{
	return from_ansi<1024>(ansi_string);
}

inline
StringW from_ansi_ex(const Char* ansi_string)
{
	return impl::from_ansi< impl::DynamicBuffer<CharW> >(ansi_string);
}

inline
StringW from_ansi_ex(const String& ansi_string)
{
	return from_ansi_ex(ansi_string.c_str());
}

//////////////////////////////////////////////////////////////////////////
template<Int MaxLen>
String to_ansi(const CharW* wide_string)
{
	return impl::to_ansi< impl::StaticBuffer<Char, MaxLen> >(wide_string);
}

inline
String to_ansi_1024(const CharW* wide_string)
{
	return to_ansi<1024>(wide_string);
}

template<Int MaxLen>
String to_ansi(const StringW& wide_string)
{
	return to_ansi<MaxLen>(wide_string.c_str());
}

inline
String to_ansi_1024(const StringW& wide_string)
{
	return to_ansi<1024>(wide_string);
}

inline
String to_ansi_ex( const CharW* wide_string )
{
	return impl::to_ansi< impl::DynamicBuffer<Char> >(wide_string);
}

inline
String to_ansi_ex(const StringW& wide_string)
{
	return to_ansi_ex(wide_string.c_str());
}

//////////////////////////////////////////////////////////////////////////
namespace impl{

template<typename Buffer>
StringW from_utf8( const Char* ansiString )
{
	Size ansiStringLen = strlen(ansiString);
	Size widesize = impl::from_utf8_count(ansiString, ansiStringLen);
	if (widesize == -1)
	{
		ttThrow("Error in conversion.");
	}

	Buffer buffer(widesize);
	if(widesize > buffer.size())
	{
		ttThrow("Error in conversion.");
	}

	Size convresult = impl::from_utf8(buffer.buffer(), buffer.size(), ansiString, ansiStringLen);

	if (convresult != widesize)
	{
		ttThrow("La falla!");
	}

	if(widesize > 1)
		return StringW(buffer.buffer(), buffer.buffer() + widesize);

	return StringW();
}

template<typename Buffer>
String to_utf8( const CharW* wideString )
{
	Size wideStringLen = wcslen(wideString);
	Size utf8size = impl::to_utf8_count(wideString, wideStringLen);
	if (utf8size == 0)
	{
		ttThrow("Error in conversion.");
	}

	Buffer buffer(utf8size);
	if(utf8size > buffer.size())
	{
		ttThrow("Error in conversion.");
	}

	Size convresult = impl::to_utf8(buffer.buffer(), buffer.size(), wideString, wideStringLen);

	if (convresult != utf8size)
	{
		ttThrow("La falla!");
	}

	if(utf8size > 1)
		return String(buffer.buffer(), buffer.buffer() + utf8size);

	return String();
}

} //namespace impl

//////////////////////////////////////////////////////////////////////////
template<Int MaxLen>
StringW from_utf8(const Char* ansi_string)
{
	return impl::from_utf8< impl::StaticBuffer<CharW, MaxLen> >(ansi_string);
}

inline
StringW from_utf8_1024(const Char* ansi_string)
{
	return from_utf8<1024>(ansi_string);
}

template<Int MaxLen>
StringW from_utf8(const String& ansi_string)
{
	return from_utf8<MaxLen>(ansi_string.c_str());
}

inline
StringW from_utf8_1024(const String& ansi_string)
{
	return from_utf8<1024>(ansi_string);
}

inline
StringW from_utf8_ex(const String& ansi_string)
{
	return from_utf8_ex(ansi_string.c_str());
}

//////////////////////////////////////////////////////////////////////////
template<Int MaxLen>
String to_utf8(const CharW* wide_string)
{
	return impl::to_utf8< impl::StaticBuffer<Char, MaxLen> >(wide_string);
}

inline
String to_utf8_1024(const CharW* wide_string)
{
	return to_utf8<1024>(wide_string);
}

template<Int MaxLen>
String to_utf8(const StringW& wide_string)
{
	return to_utf8<MaxLen>(wide_string.c_str());
}

inline
String to_utf8_1024(const StringW& wide_string)
{
	return to_utf8<1024>(wide_string);
}

inline
String to_utf8_ex( const CharW* wide_string )
{
	return impl::to_utf8< impl::DynamicBuffer<Char> >(wide_string);
}

inline
String to_utf8_ex(const StringW& wide_string)
{
	return to_utf8_ex(wide_string.c_str());
}

} //namespace utils
} //namespace tt
